; =============================================================================
;A Entrada do Kernel

; 	O ponto de entrada do kernel é um pedaco de código que é executado PRIMEIRO,
; quando o bootloader chama seu kernel.
;	Este pedaço de código é quase sempre escrito em linguagem assembly por causa
; de algumas coisas, tal como criar uma nova pilha ou carregar uma nova GDT, IDT,
; ou registros de segmento, são coisas que você simplesmente não consegue no
; seu código C.
;	Em muitos kernels principiantes assim como outros kernels mais profissionais,
; mais grandes, vão por _todo do seu código assembly neste único arquivo, e por
; _todo o resto das fontes em vários arquivos fontes C.

;	Se você entende até mesmo uma pequena quantia de assembly, o código atual
; neste arquivo deve ser muito reto a frente. Como ao longo do código mostra,
; _todo este arquivo faz é carregar uma nova pilha de 8KByte, e então pular num
; loop infinito.
;	A pilha é uma pequena área da memória, mas é usada para guardar ou passar
; argumentos para funções em C. É também usada para segurar variáveis locais que
; você declara e usa dentro das suas funções. Qualquer outras variáveis globais
; são guardadas nas seções de dados e BSS. As linhas entre os blocos 'mboot' e
; 'stublet' criam uma assinatura especial que o GRUB usa para verificar que a
; saída binária que está para carregar é, de fato, um kernel.
;	Também não lute para compreender o cabeçalho de multiboot.



; Este eh o ponto de entrada do kernel.
; Podemos chamar o kmain aqui, ou podemos usa-lo para configurar a pilha
; ou outras coisas uteis, como por exemplo, configurar o GDT...
; Note que interrupcoes estao desabilitadas neste momento.
; Tratamento de interrupcoes eh pra depois!
;=======================================================

[BITS 32]
global start
start:
    mov esp, _sys_stack     ; Aponta a pilha para a sua nossa area de pilha
    jmp stublet

; Esta parte DEVE ser '4Byte' alinhada. Entao resolvemos isso usando 'ALIGN 4'
ALIGN 4
mboot:
	; Macros multiboot para fazer que as proximas linhas possam ser mais legiveis
    MULTIBOOT_PAGE_ALIGN	equ 1<<0 ; Load kernel and modules on a page boundary
    MULTIBOOT_MEMORY_INFO	equ 1<<1 ; Provide your kernel with memory info
    MULTIBOOT_AOUT_KLUDGE	equ 1<<16
    MULTIBOOT_HEADER_MAGIC	equ 0x1BADB002 ; Multiboot Magic value
    MULTIBOOT_HEADER_FLAGS	equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO | MULTIBOOT_AOUT_KLUDGE
    MULTIBOOT_CHECKSUM	equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
    EXTERN code, bss, end

    ; Este eh o cabeçalho do multiboot GRUB. Uma assinatura de boot.
    dd MULTIBOOT_HEADER_MAGIC   ; GRUB will search for this value on each
    							; 4-byte boundary in your kernel file
    dd MULTIBOOT_HEADER_FLAGS   ; How GRUB should load your file / settings
    dd MULTIBOOT_CHECKSUM       ; To ensure that the above values are correct

    ; AOUT kludge - precisa ser endereços físicos.
    ; ANOTE ISSO: O script de linker preenche os dados para uns destes!
    dd mboot ; Make 'mboot' accessible from C.
    dd code  ; Start of the '.text' section.
    dd bss   ; Start of the .bss section.
    dd end   ; End of the last loadable section.
    dd start


; ========= CHAMADA DO KMAIN =========
; Este eh um laco sem fim.
; Chamamos o kmain antes disso...
stublet:
    extern kmain
    call kmain
    jmp $
; =====================================

; Esta eh a definicao da sua secao de BSS.
; Neste momento vamos usar apenas para armazenar a pilha.
; Lembre-se que uma pilha atualmente cresce para baixo,
; por isso nos declaramos o tamanho dos dados antes de declarar
; o identificador '_sys_stack'
SECTION .bss
   resb 8192               ; Reserva 8KBytes de memoria
_sys_stack:



;==============================================================================
;================= O Script de Linker ==================

;	O Linker é a ferramenta que toma todos os seus arquivos compilados e
; junta-os então em um único arquivo binário. Um arquivo binário pode ter vários
; formatos: Flat, AOUT, COFF, PE, e ELF são os mais comuns.
;	O linker que nós escolhemos em nosso conjunto de ferramentas foi o linker LD.
; Este é um ótimo linker multi-propósito com um extenso conjunto de recursos.
; Há versões existentes do LD que podem fazer um binário sair em qualquer formato
; que você deseja. Apesar do formato que você escolha, sempre haverá 3 'seções'
; ('sections') no arquivo final. 'Texto' ('Text') ou 'Código' ('Code') é o
; executável em sí. A seção de 'Dados' ('Data' section) é para valores
; inicializados do seu código, tal como você declara um variável e lhe atribui o
; valor 5. O valor de 5 poderá ser armazenado na seção de 'Dados' ('Data' section).
; A última seção é chamada seção 'BSS' ('BSS' section). O 'BSS' consiste de dados
; não inicializados; este guarda quaisquer arranjos (arrays) que você não
; atribuiu quaisquer valores a eles, por exemplo. 'BSS' é uma seção virtual:
; Esta não existe na imagem binária, mas este existem na memória quando seu
; binário é carregado.

;	O que se segue abaixo é um Script para o Linker LD. Há 3 palavras-chaves
; maiores que podemos retirar deste script de linker para ser analisados:
; OUTPUT_FORMAT vai dizer ao LD qual imagem binária vai ser criada. Para fazer
; isto simples, nós persistiremos para usar uma imagem "binária" ("binary").
; ENTRY vai dizer ao linker qual arquivo objeto a ser juntado vai ser o primeiro
; arquivo da lista. Nós desejaremos a versão compilada de 'start.asm' chamada
; 'start.o' para ser o primeiro arquivo objeto a ser juntado, porque este é o
; ponto de entrada do kernel. A próxima linha é 'phys'. Está não é uma
; palavra-chave, mas uma variável para ser usada no script de linker. Neste
; caso, nós vamos usa-la como um ponto para um endereço de memória: um ponteiro
; para 1MByte, onde nosso binário estará sendo carregado e rodará. A 3ª
; palavra-chave é SECTIONS. Se você estudar este script de linker, você vai ver
; que se define 3 seções principais: '.text', '.data', e '.bss'.
; Há 3 variáveis definidas também: 'code', 'data', 'bss', e 'end'. Não fique
; confuso com isto: as 3 variáveis que você vê são atualmente variáveis que
; estão em nosso arquivo de inicialização, start.asm. ALIGN(4096) assegura que
; cada seção inicie em um limite de 4096byte. Neste caso, asseguraremos que cada
; seção começará em uma 'página' em separado da memória.

; === Conteudo de linker.ld

;OUTPUT_FORMAT("binary")
;ENTRY(start)
;phys = 0x00100000;
;SECTIONS
;{
;  .text phys : AT(phys) {
;    code = .;
;    *(.text)
;    *(.rodata)
;    . = ALIGN(4096);
;  }
;  .data : AT(phys + (data - code))
;  {
;    data = .;
;   *(.data)
;    . = ALIGN(4096);
;  }
;  .bss : AT(phys + (bss - code))
;  {
;    bss = .;
;    *(.bss)
;    . = ALIGN(4096);
;  }
;  end = .;
;}
